//
//  QHBinimageMan.swift
//  QHBinimageMan
//
//  Created by Anakin chen on 2021/3/16.
//

import Cocoa

class QHBinimageMan: NSObject {
    
    // [macos - CVPixelBufferRef to NSImage](https://stackoverflow.com/questions/10318260/cvpixelbufferref-to-nsimage)
    class func img2pb(image: NSImage) -> CVPixelBuffer? {
        let cg_image = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
        
        let w = Int(image.size.width)
        let h = Int(image.size.height)
        
        let opt = [kCVPixelFormatCGImageCompatibility: true, kCVPixelBufferCGBitmapContextCompatibilityKey: true, kCVPixelBufferIOSurfacePropertiesKey: [String: Any]()] as CFDictionary
        
        var temp_pb: CVPixelBuffer?
        let r = CVPixelBufferCreate(kCFAllocatorDefault, w, h, kCVPixelFormatType_32ARGB, opt, &temp_pb);
        
        if r != kCVReturnSuccess {
            print("CVPixelBufferCreate fail")
            return nil
        }
        
        guard let pb = temp_pb else {
            print("CVPixelBuffer fail")
            return nil
        }
        
        let flags = CVPixelBufferLockFlags(rawValue: 0)
        CVPixelBufferLockBaseAddress(pb, flags)
        let pb_data = CVPixelBufferGetBaseAddress(pb)
        
        let bpc = 8
        let cs = CGColorSpaceCreateDeviceRGB()
        let bi = CGImageAlphaInfo.premultipliedFirst.rawValue
        let b_row = CVPixelBufferGetBytesPerRow(pb)
        
        guard let ctx = CGContext(data: pb_data, width: w, height: h, bitsPerComponent: bpc, bytesPerRow: b_row, space: cs, bitmapInfo: bi) else {
            print("CGContext fail")
            return nil
        }
        ctx.draw(cg_image!, in: CGRect(x: 0, y: 0, width: w, height: h))
        CVPixelBufferUnlockBaseAddress(pb, flags)
        
        return pb;
    }
    
    class func pb2img(pb: CVPixelBuffer) -> NSImage {
        // [Swift NSImage到CGImage](https://www.it1352.com/519390.html)
//        guard let s = CGImageSourceCreateWithData(image.tiffRepresentation! as CFData, nil) else { return nil }
//        let cg_image = CGImageSourceCreateImageAtIndex(s, 0, nil)
        
        let w = CVPixelBufferGetWidth(pb)
        let h = CVPixelBufferGetHeight(pb)
        let ciImage = CIImage(cvImageBuffer: pb)

        let context = CIContext(options: nil)
        let cgImage = context.createCGImage(ciImage, from: CGRect(x: 0, y: 0, width: w, height: h))

        let img = NSImage(cgImage: cgImage!, size: CGSize(width: w, height: h))
        
        return img
    }
    
    class func img2gray(pb: CVPixelBuffer) {
        let w = CVPixelBufferGetBytesPerRow(pb)/4
        let h = CVPixelBufferGetHeight(pb)
        
        let flags = CVPixelBufferLockFlags(rawValue: 0)
        CVPixelBufferLockBaseAddress(pb, flags)
        let pb_data = CVPixelBufferGetBaseAddress(pb)
        let data = unsafeBitCast(pb_data, to: UnsafeMutablePointer<UInt8>.self)
        for y in 0..<h {
            for x in 0..<w {
                let offset = 4 * (y * w + x)
                
//                let alpha = data[offset]
                // constant half3 kRec709Luma = half3(0.2126, 0.7152, 0.0722);
                let red = Float(data[offset+1]) * 0.2126
                let green = Float(data[offset+2]) * 0.7152
                let blue = Float(data[offset+3]) * 0.0722
                let v = UInt8(red + green + blue)
                
                data[offset+1] = v
                data[offset+2] = v
                data[offset+3] = v
            }
        }
        CVPixelBufferUnlockBaseAddress(pb, flags)
    }
    
    // [如何在swift中从nsimage创建灰度图像？](https://www.it1352.com/898485.html)
    class func img2gray2(image: NSImage) -> NSImage {
        let cgRef = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
        let representation = NSBitmapImageRep(cgImage: cgRef!)
        let newRep = representation.converting(to: NSColorSpace.genericGray, renderingIntent: NSColorRenderingIntent.default)
//        let pngData = newRep!.representation(using: NSBitmapImageRep.FileType.png, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: 1.0])
//        let m = NSImage(data: pngData!)
        let m = NSImage(size: image.size)
        m.addRepresentation(newRep!)
        
        return m
    }
    
    class func pb2binimg(pb: CVPixelBuffer, ratio: Int, minbin: UInt8, maxbin: UInt8) -> String {
        let w = CVPixelBufferGetBytesPerRow(pb)/4
        let h = CVPixelBufferGetHeight(pb)
        let ss = max(ratio, 1)
        
        let flags = CVPixelBufferLockFlags(rawValue: 0)
        CVPixelBufferLockBaseAddress(pb, flags)
        let pb_data = CVPixelBufferGetBaseAddress(pb)
        var matrixBitmap: String = ""
        let data = unsafeBitCast(pb_data, to: UnsafeMutablePointer<UInt8>.self)
        for y in 0..<h {
            if y%ss == 0 {
                var matrixLine: String = ""
                for x in 0..<w {
                    let offset = 4 * (y * w + x)
                    let v = data[offset+1]
                    
                    if x%ss == 0 {
                        if v > minbin && v < maxbin {
                            matrixLine += "1"
                        }
                        else {
                            matrixLine += "0"
                        }
                    }
                }
                matrixBitmap += matrixLine + "\n"
            }
        }
        CVPixelBufferUnlockBaseAddress(pb, flags)
        
        return matrixBitmap
    }
}
